/**
 * Project Name:payment File Name:SignUtils.java Package Name:cn.swiftpass.utils.payment.sign
 * Date:2014-6-27下午3:22:33
 */
package com.acooly.module.openapi.client.provider.wsbank.utils;


import com.acooly.core.utils.Reflections;
import com.acooly.core.utils.Strings;
import com.acooly.module.openapi.client.provider.wsbank.domain.WsbankAlias;
import com.acooly.module.openapi.client.provider.wsbank.message.WsbankUploadImgRequest;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

/**
 * ClassName:SignUtils Function: 签名用的工具箱 Date: 2014-6-27 下午3:22:33
 *
 * @author
 */
@Slf4j
public class SignUtils {

  public static final String RSA_CHIPER = "RSA/ECB/PKCS1Padding";

  /** 编码 */
  public static final String ENCODE = "UTF-8";

  /** 1024bit 加密块 大小 */
  public static final int ENCRYPT_KEYSIZE = 117;
  /** 1024bit 解密块 大小 */
  public static final int DECRYPT_KEYSIZE = 128;

  /**
   * 过滤参数
   *
   * @param sArray
   * @return
   * @author
   */
  public static Map<String, String> paraFilter(Map<String, String> sArray) {
    Map<String, String> result = new HashMap<String, String>(sArray.size());
    if (sArray == null || sArray.size() <= 0) {
      return result;
    }
    for (String key : sArray.keySet()) {
      String value = sArray.get(key);
      if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
        continue;
      }
      result.put(key, value);
    }
    return result;
  }

  /**
   * <一句话功能简述> <功能详细描述>将map转成String
   *
   * @param payParams
   * @return
   * @see [类、类#方法、类#成员]
   */
  public static String payParamsToString(Map<String, String> payParams) {
    return payParamsToString(payParams, false);
  }

  public static String payParamsToString(Map<String, String> payParams, boolean encoding) {
    return payParamsToString(new StringBuilder(), payParams, encoding);
  }

  /**
   * @param payParams
   * @return
   * @author
   */
  public static String payParamsToString(
      StringBuilder sb, Map<String, String> payParams, boolean encoding) {
    buildPayParams(sb, payParams, encoding);
    return sb.toString();
  }

  /**
   * @param payParams
   * @return
   * @author
   */
  public static void buildPayParams(
      StringBuilder sb, Map<String, String> payParams, boolean encoding) {
    List<String> keys = new ArrayList<String>(payParams.keySet());
    Collections.sort(keys);
    for (String key : keys) {
      sb.append(key).append("=");
      if (encoding) {
        sb.append(urlEncode(payParams.get(key)));
      } else {
        sb.append(payParams.get(key));
      }
      sb.append("&");
    }
    sb.setLength(sb.length() - 1);
  }

  public static String urlEncode(String str) {
    try {
      return URLEncoder.encode(str, "UTF-8");
    } catch (Throwable e) {
      return str;
    }
  }

  /**
   * 遍历以及根据重新排序
   *
   * @param sortedParams
   * @return
   */
  public static String getSignContent(Map<String, String> sortedParams) {
    StringBuffer content = new StringBuffer();
    List<String> keys = new ArrayList<String>(sortedParams.keySet());
    Collections.sort(keys);
    int index = 0;
    for (int i = 0; i < keys.size(); i++) {
      String key = keys.get(i);
      String value = sortedParams.get(key);
      if (Strings.isNotBlank(value)) {
        content.append((index == 0 ? "" : "&") + key + "=" + value);
        index++;
      }
    }
    return content.toString();
  }

  /**
   * 获取代签map
   *
   * @param source
   * @return
   */
  public static SortedMap<String, String> getSignDataMap(WsbankUploadImgRequest source) {
    SortedMap<String, String> signData = Maps.newTreeMap();
    Set<Field> fields = Reflections.getFields(source.getClass());
    String key = null;
    Object value = null;
    for (Field field : fields) {
      value = Reflections.getFieldValue(source, field.getName());
      if (value == null) {
        continue;
      }
      WsbankAlias baofuAlias = field.getAnnotation(WsbankAlias.class);
      if (baofuAlias == null) {
        continue;
      } else {
        if (!baofuAlias.sign()) {
          continue;
        }
        key = baofuAlias.value();
      }
      if (Strings.isNotBlank((String) value)) {
        signData.put(key, (String) value);
      }
    }
    return signData;
  }

  /**
   * 根据String获取公钥 - RSA
   *
   * @param encodePublicKey
   * @return
   * @throws NoSuchAlgorithmException
   * @throws InvalidKeySpecException
   */
  public static PublicKey getPublicKey(String encodePublicKey) throws NoSuchAlgorithmException,
          InvalidKeySpecException {
    byte[] publicKeyKeyBytes = Base64.getDecoder().decode(encodePublicKey);
    KeyFactory kf = KeyFactory.getInstance("RSA"); // or "EC" or whatever
    PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyKeyBytes));
    return publicKey;
  }
}
